package DEEPERsource.DEEPERsource.source.deeper;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.io.StringReader;
import java.util.Map;

import exceptions.GraphException;
import exceptions.NoSuchWordException;

import parser.StructuredSentence;

import jung.entities.Graph;
import jung.entities.NewPath;

public class Interaction implements Comparable<Interaction>, Serializable{
	
	private static final long serialVersionUID = 2L;
	
	//proteins that take part in interaction
	public Protein p1;
	public Protein p2;
	//interaction type as defined in xml dataset (physical, bind etc.)
	public String type;
	//interaction ID as defined in xml dataset
	public String id;
	//sentence ID as defined in xml dataset
	public String sentId;
	//sentence ID as defined in original dataset
	public String origSentId;
	//interaction class (positive, negative, straight, inverse)
	public InteractionType status;
	//for some interactions we know that they are negative in advance, so keep it
	public InteractionType predefinedStatus;
	
	//all parsing information 
	public String sentence;
	public transient NewPath depPath;
	public transient NewPath parsePath;
	public transient Graph depTree;
	public transient Graph parseTree;
	public StructuredSentence struct;
	
	//abbreviations in sentence,introduced by Preprocessor (ccoTerms, ccoIds, etc.) 
	public Map<String,String> abbr;
	
	//interaction class, as predicted by classifier (used in UI)
	public transient String predClass;
	
	public void initInteraction() throws GraphException, NoSuchWordException {
		int ind1 = struct.getIndex(p1.name_mod)+1;
		int ind2 = struct.getIndex(p2.name_mod)+1;
		if(ind1==0 || ind2==0)
			throw new NoSuchWordException("Protein was not found. Indices "+ind1+", "+ind2);
		if(ind1==ind2){
			throw new NoSuchWordException("Proteins occur in one word. No path exists.");
		}
		depPath = depTree.getNewPath(depTree.findVertex(ind1), depTree.findVertex(ind2));
		parsePath = parseTree.getNewPath(parseTree.findVertex(ind1), parseTree.findVertex(ind2));
	}
	
	public void erase(){
		p1 = null;
		p2 = null;
		abbr = null;
		depPath = null;
		parsePath = null;
		depTree = null;
		parseTree = null;
		struct = null;
	}

	public int compareTo(Interaction i) {
		if(status.ordinal()>i.status.ordinal()){
			return 1;
		}else if(status.ordinal()<i.status.ordinal()){
			return -1;
		}
		return 0;
	}
	
	public String getClearSentence(){
		return sentence.replace(p1.name_mod, p1.name).replace(p2.name_mod, p2.name);
	}
	
	public String toString(){
		return id;
	}
	
	private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
		in.defaultReadObject();
		String str = (String)in.readObject();
		if(str!=null){
			BufferedReader reader = new BufferedReader(new StringReader(str));
			depPath = NewPath.deserialize(reader);
			reader.close();
		}
		str = (String)in.readObject();
		if(str!=null){
			BufferedReader reader = new BufferedReader(new StringReader(str));
			parsePath = NewPath.deserialize(reader);
			reader.close();
		}
		//Limiting memory usage
		str = (String)in.readObject();
		if(str!=null){
			BufferedReader reader = new BufferedReader(new StringReader(str));
			depTree = Graph.deserialize(reader);
			reader.close();
		}
		str = (String)in.readObject();
		if(str!=null){
			BufferedReader reader = new BufferedReader(new StringReader(str));
			parseTree = Graph.deserialize(reader);
			reader.close();
		}
	}

	private void writeObject(ObjectOutputStream out) throws IOException {
		out.defaultWriteObject();
		if(depPath!=null){
			out.writeObject(depPath.serialize());
		}else{
			out.writeObject(null);
		}
		if(parsePath!=null){
			out.writeObject(parsePath.serialize());
		}else{
			out.writeObject(null);
		}
		if(depTree!=null){
			out.writeObject(depTree.serialize());
		}else{
			out.writeObject(null);
		}
		if(parseTree!=null){
			out.writeObject(parseTree.serialize());
		}else{
			out.writeObject(null);
		}
	}
	
	public String getType(){
		String type = "";
		int real = status.ordinal();
		int pred = Integer.parseInt(predClass);
		if(real == InteractionType.FALSE.ordinal()){
			if(real == pred)
				type = "TN";
			else
				type = "FP";
		}else{
			if(real == pred)
				type = "TP";
			else
				if(pred==InteractionType.FALSE.ordinal())
					type = "FN";
				else
					type = "WD";
		}
		return type;
	}
}
